﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Duellum.Core.Resources;
using JpLabs.DynamicCode;

namespace Duellum.Core
{
	public class DuelPluginXmlConfigReader : IDisposable
	{
		public XDocument XDoc { get; private set; }

		private readonly DuelDomain domain;
		private DuelSerializer serializer;
		private string[] namespaces;
		
		public DuelPluginXmlConfigReader(DuelDomain domain, Uri uriXmlResource, params string[] namespaces)
		{
			this.domain = domain;
			
			Init(uriXmlResource, namespaces);
		}
		
		public void Init(Uri uriXmlResource, params string[] namespaces)
		{
			this.namespaces = namespaces;
			
			using (var xmlStream = DuelResources.GetStreamFromUri(uriXmlResource)) {
				
				//TODO: xmlStream content should be validated, like this:
				//XmlReaderSettings settings = new XmlReaderSettings();
				//settings.Schemas.Add(schema);
				//settings.ValidationType = ValidationType.Schema;
				//StringReader sr = new StringReader(xmlDoc);
				//XmlReader reader = XmlReader.Create(sr, settings);
				
				XDoc = XDocument.Load(XmlReader.Create(xmlStream));
			}

			serializer = new DuelSerializer();
		    serializer.Compiler.AddReferences(
		        XDoc.XPathSelectElements("/duellum/compiler/reference").Select(x => x.Value)
		    );
			
		    serializer.Compiler.AddUsings(
		        XDoc.XPathSelectElements("/duellum/compiler/using").Select(x => x.Value)
		    );
		}

		public IEnumerable<DuelPluginName> GetReferencedPlugins()
		{
			return null;
		}

		public IEnumerable<DuelType> GetTypes()
		{
			var types = XDoc.XPathSelectElements("/duellum/types/*");
			using (var serializer = new DuelSerializer()) {
				return (
					types.Select(x => serializer.DeserializeDuelType(domain, x, namespaces))
				).ToArray();
			}
		}

		//public IEnumerable<DuelDecoration> GetExtendedTypes()
		//{
		//    var types = XDoc.XPathSelectElements("/duellum/extensions/*");
		//    return null;
		//}

		public IEnumerable<DuelDecoration> GetDecorations()
		{
		    var types = XDoc.XPathSelectElements("/duellum/decorations/*");
		    return (
		        types.Select(x => (DuelDecoration)serializer.DeserializeDuelType(domain, x, namespaces))
		    ).ToArray();
		}

		public void Dispose()
		{
			if (serializer != null) serializer.Dispose();
		}
	}
}
